package com.mg.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mg.common.Constants;
import com.mg.dto.PurchaseSaleDto;
import com.mg.dto.SimpleResult;
import com.mg.mapper.*;
import com.mg.model.*;
import com.mg.service.PurchaseSaleService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by mg1213 on 2018/3/18.
 */
@Service
public class PurchaseSaleServiceImpl implements PurchaseSaleService {
    @Autowired
    private PurchaseSaleMapper purchaseSaleMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PowerAccountMapper powerAccountMapper;
    @Autowired
    private PurchaseSaleRecordMapper purchaseSaleRecordMapper;
    @Autowired
    private ContractMapper contractMapper;

    private Logger logger = LogManager.getLogger(PurchaseSaleServiceImpl.class.getName());

    @Override
    public PageInfo<PurchaseSaleDto> selectPageInfo(PurchaseSaleDto purchaseSaleDto, int start, int limit) {
        PageHelper.offsetPage(start, limit);
        if (purchaseSaleDto.getState() != null && Constants.ALL_STRING.equals(purchaseSaleDto.getState())) {
            purchaseSaleDto.setState(null);
        }
        List<PurchaseSaleDto> resultList = purchaseSaleMapper.selectPageInfo(purchaseSaleDto);
        PageInfo<PurchaseSaleDto> result = new PageInfo<>(resultList);
        return result;
    }

    @Override
    public SimpleResult insertPurchaseSale(PurchaseSale record) {
        SimpleResult result = new SimpleResult();
        try {
            //收购
            if (Constants.PURCHASE.equals(record.getType())) {
                User user = new User();
                user.setId(record.getUserId());
                user = userMapper.selectOne(user);
                BigDecimal money = record.getPrice().multiply(record.getTotalNum());
                BigDecimal effectiveMoney = user.getBalance().subtract(user.getFrozeMoney());
                if (money.compareTo(effectiveMoney) > 0) {
                    result.setSuccess(false);
                    result.setMsg("余额不足");
                    return result;
                }
                BigDecimal frozeMoney = user.getFrozeMoney();

                frozeMoney = frozeMoney.add(money);
                user.setFrozeMoney(frozeMoney);
                user.setBalance(null);
                user.setUpdateTime(new Date());
                userMapper.updateByPrimaryKeySelective(user);
            } else {
                PowerAccount powerAccount = new PowerAccount();
                powerAccount.setContractId(record.getContractId());
                powerAccount.setUserId(record.getUserId());
                powerAccount = powerAccountMapper.selectOne(powerAccount);
                BigDecimal effectiveNum =powerAccount.getComputingPowerNum().subtract(powerAccount.getFrozenComputingPowerNum());
                if (effectiveNum.compareTo(record.getTotalNum()) < 0) {
                    result.setSuccess(false);
                    result.setMsg("算力不足");
                    return result;
                }
                BigDecimal frozenComputingPowerNum = powerAccount.getFrozenComputingPowerNum();
                frozenComputingPowerNum = frozenComputingPowerNum.add(record.getTotalNum());
                Contract contract = contractMapper.selectByPrimaryKey(record.getContractId());
                BigDecimal  frozenComputingPower = record.getTotalNum().multiply(contract.getComputingPower());
                frozenComputingPower= powerAccount.getFrozenComputingPower().add(frozenComputingPower);
                powerAccount.setComputingPower(null);
                powerAccount.setComputingPowerNum(null);
                powerAccount.setFrozenComputingPowerNum(frozenComputingPowerNum);
                powerAccount.setFrozenComputingPower(frozenComputingPower);
                powerAccount.setUpdateTime(new Date());
                powerAccountMapper.updateByPrimaryKeySelective(powerAccount);
            }
            record.setCreateTime(new Date());
            purchaseSaleMapper.insert(record);
        } catch (Exception e) {
            result.setSuccess(false);
            result.setMsg("新增售购信息失败 系统未知异常");
            logger.error("新增售购信息失败 系统未知异常", e);
        }
        return result;
    }

    @Override
    public SimpleResult updatePurchaseSale(PurchaseSale record) {
        SimpleResult result = new SimpleResult();
        try {
            PurchaseSale record1 = new PurchaseSale();
            record1.setId(record.getId());
            record1 = purchaseSaleMapper.selectOne(record1);
            if (record1 == null) {
                result.setSuccess(false);
                result.setMsg("该售购信息不存在，请刷新重试！");
            } else {

                record.setUpdateTime(new Date());
                purchaseSaleMapper.updateByPrimaryKeySelective(record);
            }

        } catch (Exception e) {
            result.setSuccess(false);
            result.setMsg("更新售购信息失败 系统未知异常");
            logger.error("更新售购信息失败 系统未知异常", e);
        }
        return result;
    }

    @Override
    public SimpleResult deletePurchaseSale(String ids) {
        SimpleResult result = new SimpleResult();
        try {
            String[] idArr = ids.split(",");
            for (String id : idArr) {

                purchaseSaleMapper.deleteByPrimaryKey(Integer.parseInt(id));
            }
        } catch (Exception e) {
            result.setSuccess(false);
            result.setMsg("删除售购信息失败 系统未知异常");
            logger.error("删除售购信息失败 系统未知异常", e);
        }
        return result;
    }

    @Override
    public PurchaseSaleDto getPurchaseSale(PurchaseSaleDto purchaseSaleDto) {
        List<PurchaseSaleDto> purchaseSaleDtos = purchaseSaleMapper.selectPageInfo(purchaseSaleDto);
        if (purchaseSaleDtos.isEmpty()) {
            return new PurchaseSaleDto();
        } else {
            return purchaseSaleDtos.get(0);

        }
    }

    @Override
    public SimpleResult tradeContract(Integer id, Integer userId, BigDecimal num) {
        SimpleResult result = new SimpleResult();
        User user = new User();
        user.setId(userId);
        user = userMapper.selectOne(user);
        if (user == null) {
            result.setSuccess(false);
            result.setMsg("用户信息不存在");
        } else {
            PurchaseSale purchaseSale = new PurchaseSale();
            purchaseSale.setId(id);
            purchaseSale = purchaseSaleMapper.selectOne(purchaseSale);
            if (purchaseSale == null) {
                result.setMsg("信息不存在,请刷新重试！");
                result.setSuccess(false);
            } else {
                //剩余数量大于购买数量
                if (purchaseSale.getRemainderNum().compareTo(num) > -1) {
                    //出售
                    if (Constants.PURCHASE.equals(purchaseSale.getType())) {
                        result = saleContract(user, purchaseSale, num);
                    } else {
                        result = purchaseContract(user, purchaseSale, num);
                    }
                } else {
                    result.setSuccess(false);
                    result.setMsg("购买数量大于最大数量");
                }

            }
        }


        return result;
    }

    @Override
    public Map<String, Object> getDetail(PurchaseSaleDto record, Integer userId) {
        Map<String, Object> result = new HashMap<>();
        PurchaseSaleDto purchaseSaleDto = getPurchaseSale(record);
        PowerAccount powerAccount = new PowerAccount();
        powerAccount.setUserId(userId);
        powerAccount.setContractId(purchaseSaleDto.getContractId());
        powerAccount=powerAccountMapper.selectOne(powerAccount);
        result.put("purchaseSale",purchaseSaleDto);
        result.put("powerAccount",powerAccount);
        return result;
    }

    private SimpleResult purchaseContract(User purchaseUser, PurchaseSale purchaseSale, BigDecimal num) {
        SimpleResult result = new SimpleResult();
        Contract contract = contractMapper.selectByPrimaryKey(purchaseSale.getContractId());
        if(contract==null){
            result.setMsg("合约不存在");
            result.setSuccess(false);
            return result;
        }
        BigDecimal money = num.multiply(purchaseSale.getPrice());
        BigDecimal effectiveMoney = purchaseUser.getBalance().subtract(purchaseUser.getFrozeMoney());
        if (effectiveMoney.compareTo(money) > -1) {
            //合约算力表
            PowerAccount salePowerAccount = new PowerAccount();
            salePowerAccount.setUserId(purchaseSale.getUserId());
            salePowerAccount.setContractId(purchaseSale.getContractId());
            salePowerAccount = powerAccountMapper.selectOne(salePowerAccount);
            updateSalePowerAccount(contract,salePowerAccount, num,true);
            PowerAccount purchasePowerAccount = new PowerAccount();
            purchasePowerAccount.setUserId(purchaseUser.getId());
            purchasePowerAccount.setContractId(purchaseSale.getContractId());
            purchasePowerAccount = powerAccountMapper.selectOne(purchasePowerAccount);

            if (purchasePowerAccount == null) {
                insertPowerAccount(contract,purchaseSale, num, purchaseUser.getId());
            } else {
                updatePowerAccount(contract,purchasePowerAccount, num);
            }
            //余额修改
            User saleUser = new User();
            saleUser.setId(purchaseSale.getUserId());
            saleUser = userMapper.selectOne(saleUser);
            updateSaleUser(saleUser, money);
            updatePurchaseUer(purchaseUser, money,false);
            //添加记录
            insertPurchaseSaleRecord(purchaseSale.getContractId(), saleUser.getId(), purchaseUser.getId(), num,purchaseSale.getPrice());
            updatePurchaseSale(purchaseSale, num);
        } else {
            result.setMsg("有效余额不足，有效余额为" + effectiveMoney);
            result.setSuccess(false);
        }
        return result;
    }

    private void updatePowerAccount(Contract contract,PowerAccount purchasePowerAccount, BigDecimal num) {
        BigDecimal power = purchasePowerAccount.getComputingPower().add(num.multiply(contract.getComputingPower()));
        purchasePowerAccount.setComputingPower(power);
        BigDecimal totalNum =purchasePowerAccount.getComputingPowerNum().add(num);
        purchasePowerAccount.setComputingPowerNum(totalNum);
        purchasePowerAccount.setFrozenComputingPower(null);
        purchasePowerAccount.setUpdateTime(new Date());
        powerAccountMapper.updateByPrimaryKeySelective(purchasePowerAccount);
    }

    private SimpleResult saleContract(User saleUser, PurchaseSale purchaseSale, BigDecimal num) {
        SimpleResult result = new SimpleResult();
        Contract contract = contractMapper.selectByPrimaryKey(purchaseSale.getContractId());
        if(contract==null){
            result.setMsg("合约不存在");
            result.setSuccess(false);
            return result;
        }
        BigDecimal money = num.multiply(purchaseSale.getPrice());
        PowerAccount salePowerAccount = new PowerAccount();
        salePowerAccount.setUserId(saleUser.getId());
        salePowerAccount.setContractId(purchaseSale.getContractId());
        salePowerAccount = powerAccountMapper.selectOne(salePowerAccount);
        if (salePowerAccount == null) {
            result.setSuccess(false);
            result.setMsg("没有该合约的算力！");
        } else {
            BigDecimal effectivePowerNum = salePowerAccount.getComputingPowerNum().subtract(salePowerAccount.getFrozenComputingPowerNum());
            if (effectivePowerNum.compareTo(num) > -1) {
                updateSalePowerAccount(contract, salePowerAccount, num,false);
                PowerAccount purchaseAccount = new PowerAccount();
                purchaseAccount.setUserId(purchaseSale.getUserId());
                purchaseAccount.setContractId(purchaseSale.getContractId());
                purchaseAccount = powerAccountMapper.selectOne(purchaseAccount);
                //不存在新增
                if (purchaseAccount == null) {
                    insertPowerAccount(contract,purchaseSale, num, purchaseSale.getUserId());
                } else {
                    updatePowerAccount(contract,purchaseAccount, num);
                }
                //余额修改
                updateSaleUser(saleUser, money);
                User purchaseUser = new User();
                purchaseUser.setId(purchaseSale.getUserId());
                purchaseUser = userMapper.selectOne(purchaseUser);
                updatePurchaseUer(purchaseUser, money,true);
                //添加记录
                insertPurchaseSaleRecord(purchaseSale.getContractId(), saleUser.getId(), purchaseUser.getId(), num,purchaseSale.getPrice());
                updatePurchaseSale(purchaseSale, num);

            } else {
                result.setMsg("该合约的有效算力不足，有效算力份数为" + effectivePowerNum);
                result.setSuccess(false);
            }
        }
        return result;
    }

    private void updateSalePowerAccount(Contract contract, PowerAccount salePowerAccount, BigDecimal num,boolean updateFrozen) {
        BigDecimal power = salePowerAccount.getComputingPower().subtract(num.multiply(contract.getComputingPower()));
        BigDecimal frozenComputingPower = salePowerAccount.getFrozenComputingPower().subtract(num.multiply(contract.getComputingPower()));
        BigDecimal powerNum = salePowerAccount.getComputingPowerNum().subtract(num);
        BigDecimal frozenComputingPowerNum = salePowerAccount.getComputingPowerNum().subtract(num);
        salePowerAccount.setComputingPower(power);
        salePowerAccount.setComputingPowerNum(powerNum);
        if(updateFrozen){
            salePowerAccount.setFrozenComputingPowerNum(frozenComputingPowerNum);
            salePowerAccount.setFrozenComputingPower(frozenComputingPower);
        }
        salePowerAccount.setUpdateTime(new Date());
        powerAccountMapper.updateByPrimaryKeySelective(salePowerAccount);
    }

    private void updateSaleUser(User saleUser, BigDecimal money) {
        BigDecimal balance = saleUser.getBalance().add(money);
        saleUser.setFrozeMoney(null);
        saleUser.setBalance(balance);
        saleUser.setUpdateTime(new Date());
        userMapper.updateByPrimaryKeySelective(saleUser);
    }

    private void updatePurchaseUer(User purchaseUser, BigDecimal money,boolean updataFrozeMoney) {
        BigDecimal purchaseBalance = purchaseUser.getBalance();
        BigDecimal frozeMoney = purchaseUser.getFrozeMoney();
        purchaseBalance = purchaseBalance.subtract(money);
        frozeMoney = frozeMoney.subtract(money);
        purchaseUser.setBalance(purchaseBalance);
        if(updataFrozeMoney){
            purchaseUser.setFrozeMoney(frozeMoney);
        }else{
            purchaseUser.setFrozeMoney(null);
        }
        purchaseUser.setUpdateTime(new Date());
        userMapper.updateByPrimaryKeySelective(purchaseUser);
    }

    private void insertPurchaseSaleRecord(Integer contractId, Integer saleUserId, Integer purchaseUserId, BigDecimal num, BigDecimal price) {
        PurchaseSaleRecord purchaseSaleRecord = new PurchaseSaleRecord();
        purchaseSaleRecord.setCreateTime(new Date());
        purchaseSaleRecord.setComputingPower(num);
        purchaseSaleRecord.setSaleUserId(saleUserId);
        purchaseSaleRecord.setPurchaseUserId(purchaseUserId);
        purchaseSaleRecord.setPrice(price);
        purchaseSaleRecord.setContractId(contractId);
        purchaseSaleRecordMapper.insert(purchaseSaleRecord);
    }

    private void insertPowerAccount(Contract contract,PurchaseSale purchaseSale, BigDecimal num, Integer userId) {
        PowerAccount purchaseAccount = new PowerAccount();
        purchaseAccount.setUserId(userId);
        purchaseAccount.setComputingPowerNum(num);
        purchaseAccount.setComputingPower(num.multiply(contract.getComputingPower()));
        purchaseAccount.setFrozenComputingPower(new BigDecimal(0));
        purchaseAccount.setFrozenComputingPowerNum(new BigDecimal(0));
        purchaseAccount.setCreateTime(new Date());
        purchaseAccount.setContractId(purchaseSale.getContractId());
        powerAccountMapper.insertSelective(purchaseAccount);
    }

    private void updatePurchaseSale(PurchaseSale purchaseSale, BigDecimal num) {
        BigDecimal remainderNum = purchaseSale.getRemainderNum().subtract(num);
        purchaseSale.setRemainderNum(remainderNum);
        purchaseSale.setTotalNum(null);
        if (remainderNum.compareTo(new BigDecimal(0)) < 1) {
            purchaseSale.setState("交易完成");
        }
        purchaseSaleMapper.updateByPrimaryKeySelective(purchaseSale);
    }
}
